package cn.tannn.tregistry.server.health;

import cn.tannn.tregistry.core.api.Server;
import cn.tannn.tregistry.core.model.InstanceMeta;
import cn.tannn.tregistry.core.service.RegistryService;
import cn.tannn.tregistry.core.service.TRegistryService;
import cn.tannn.tregistry.server.cluster.Cluster;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 默认探活实现 (服务探活
 *
 * @author <a href="https://tannn.cn/">tnnn</a>
 * @version V1.0
 * @date 2024/4/13 下午8:42
 */
@Slf4j
public class THealthChecker implements HealthChecker {

    final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

    final RegistryService registryService;
    final Cluster cluster;

    /**
     * 超时时间 20s
     */
    long timeout = 20_000;

    public THealthChecker(RegistryService registryService, Cluster cluster) {
        this.registryService = registryService;
        this.cluster = cluster;
    }

    @Override
    public void start() {
        // 30s - 探活线程 执行配置
        this.executor.scheduleWithFixedDelay(() -> {
            try {
                // 只允许 leader 探活服务实例
                Server self = cluster.self();
                if (self.isLeader() && self.isStatus()) {
                    long now = System.currentTimeMillis();
                    Map<String, Long> timestamps = TRegistryService.TIMESTAMPS;
                    log.debug("===> health checker running  timestamps : {}", timestamps);
                    timestamps.forEach((s, t) -> {
                        if ((now - t) > timeout) {
                            log.debug("===> health checker : {} is down ", s);
                            int index = s.indexOf("@");
                            String service = s.substring(0, index);
                            String url = s.substring(index + 1);
                            InstanceMeta instance = InstanceMeta.from(url);
                            registryService.unregister(service, instance);
                            TRegistryService.TIMESTAMPS.remove(s);
                        }
                    });
                }

            } catch (Exception e) {
                log.error("===> health checker running  error : {}", e.getMessage(), e);
            }
        }, 10, 30, TimeUnit.SECONDS);

    }

    @Override
    public void stop() {
        log.info("===> health checker stop ...");
        executor.shutdown();
    }
}
